import os

from django.db import models
from django.contrib import admin
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import Group
from django.utils.safestring import mark_safe
from django.shortcuts import get_object_or_404
from app import settings
from app.common import send_user_activation_mail, send_user_reset_password_mail

from django_resized import ResizedImageField


AVATAR_DIR = 'avatars'
DEFAULT_AVATAR = os.path.join(AVATAR_DIR, 'default.jpg')
DEFAULT_AVATAR_URL = os.path.join('/', settings.MEDIA_URL, DEFAULT_AVATAR)


def get_upload_path(instance, filename):
    # instance is a User instance in this case
    #_, ext = os.path.splitext(filename)
    return os.path.join(AVATAR_DIR, os.urandom(16).hex() + '.jpg')


class UserManager(BaseUserManager):
    def create_user(self, email, password, **extra_fields):
        if not email:
            raise ValueError(_('Email is required!'))
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **extra_fields):
        user = self.create_user(email, password, **extra_fields)
        user.is_active = extra_fields.get('is_active', True)
        user.is_staff = True
        user.is_superuser = True

        user.save()
        return user


class CustomUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(_('Email address'), unique=True, db_index=True)
    username = models.CharField(_('Username'), max_length=40, db_index=True)
    first_name = models.CharField(
        _('First name'), max_length=30, blank=True, null=True)
    last_name = models.CharField(
        _('Last name'), max_length=30, blank=True, null=True)
    avatar = ResizedImageField(
        size=[140, 140], upload_to=get_upload_path, crop=['middle', 'center'], force_format='JPEG', quality=95, null=True, blank=True)

    updated = models.DateTimeField(auto_now=True, db_index=True)
    date_joined = models.DateTimeField(auto_now_add=True, db_index=True)

    # required fields
    is_active = models.BooleanField(
        _('Active'), default=True, help_text=_('Whether the user can login or not.'), db_index=True)
    is_staff = models.BooleanField(_('Staff status'), default=False, help_text=_(
        'Whether the user can login to this dashboard or not.'), db_index=True)
    is_superuser = models.BooleanField(_('Superuser status'), default=False, help_text=_(
        'Grant all permissions regardless of everything, without asigning them one by one.'), db_index=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    objects = UserManager()

    class Meta:
        verbose_name = _('user')
        ordering = ('-date_joined',)

    def get_avatar_url(self):
        return self.avatar.url if self.avatar else DEFAULT_AVATAR_URL

    @admin.display(description=_('Avatar'))
    def avatar_image(self):
        return self.avatar_image_size((45, 45))

    @admin.display(description=_('Current Avatar'))
    def avatar_image_large(self):
        return self.avatar_image_size((150, 150))

    def avatar_image_size(self, size=None):
        if not isinstance(size, tuple) and not isinstance(size, list) and len(size) != 2:
            raise ValueError(
                "The 'size' parameter must be tuple '(width, height)', e.g: (75, 75)")

        return mark_safe(f'<img src="{self.get_avatar_url()}" title="{self.username}" style="width: {size[0]}px; height: {size[1]}px; border-radius: 50%">')

    @admin.display(description=_('Password'))
    def change_password(self, obj=None):
        return mark_safe("<span class='bp'><a href='../password' class='btn btn-primary btn-sm text-white'><i class='fas fa-key fa-fw'></i> %s</a></span>" % _('Change Password?'))

    def save(self, *args, **kwargs):
        if self.pk:
            old_obj = get_object_or_404(self.__class__, pk=self.pk)
            if old_obj.avatar and self.avatar.name != old_obj.avatar.name:
                # delete the old avatar
                try:
                    os.remove(os.path.join(
                        settings.MEDIA_URL, old_obj.avatar.path))
                except OSError as e:
                    print("Can't delete: ", e)

        return super().save(*args, **kwargs)

    def __str__(self):
        return self.email

    def send_activation_mail(self, req):
        return send_user_activation_mail(self, req)

    def send_reset_password_mail(self, req):
        return send_user_reset_password_mail(self, req)

    def icon(self):
        return "<i class='fa fa-user-group nav-icon'></i>"

    @admin.display(description=_('Links'))
    def total_links(self):
        return self.links.count()

    @admin.display(description=_('Clicks'))
    def total_clicks(self):
        return sum(link.clicks() for link in self.links.all())

    @admin.display(description=_('Domains'))
    def total_domains(self):
        return self.domains.count()


class CustomGroup(Group):

    class Meta:
        verbose_name = _('group')

    def icon(self):
        return "<i class='fa fa-people-group nav-icon'></i>"
